﻿// <copyright project="AsynchronousSessionAuditor" file="AsynchronousSessionAuditor.js" company="Sky Sanders">
// This source is a Public Domain Dedication. 
// http://spikes.codeplex.com
// Attribution is appreciated.
// </copyright> 


var AsynchronousSessionAuditor = {
    /// this script really should be served as a resource embedded in the assembly of the module
    /// especially to keep the keys syncronized

    pollingInterval: 60000, // 60 second polling. Not horrible, except for the server logs. ;)

    formsAuthAuditKey: ".formsauthticket", // convenience members
    aspSessionAuditKey: ".aspnetsession",

    errorCallback: function(key, xhr) {
        /// <summary>
        /// Default behavior is to redirect to Default and provide the xhr error status text
        /// in the loggedout query param.
        ///
        /// You may replace this default behaviour with your own handler. 
        /// e.g.  AsynchronousSessionAuditor.errorCallback = myMethod;
        /// </summary>
        /// <param name="key" type="String"></param>
        /// <param name="xhr" type="XMLHttpRequest"></param>
        window.location = "Default.aspx?loggedout=Error+" + xhr.statusText;
    },

    timeoutCallback: function(key, xhr) {
        /// <summary>
        /// Default behavior is to redirect to Default and provide the key value
        /// in the loggedout query param.
        ///
        /// You may replace this default behaviour with your own handler.
        /// e.g.  AsynchronousSessionAuditor.timeoutCallback= myMethod;
        /// </summary>
        /// <param name="key" type="String"></param>
        /// <param name="xhr" type="XMLHttpRequest"></param>    
        window.location = "Default.aspx?loggedout=" + key;
        // or just refresh. you will be sent to login.aspx
    },

    statusCallback: function(value) {
        /// <summary>
        /// Default behavior is to do nothing, which is not very interesting.
        /// This value is set when AsynchronousSessionAuditor.init is called
        /// </summary>
        /// <param name="value" type="String">
        /// The responseText of the audit request. Most certainly is a JavaScript Date
        /// as a number. Just cast to date to get the requested expiration dateTime.
        /// e.g. var exp = new Date(parseFloat(value)); if (isNaN(exp)){this should never happen}
        /// </param>

        window.location = "Default.aspx?loggedout=" + key;
        // or just refresh. you will be sent to login.aspx
    },

    createXHR: function() {
        /// <summary>
        /// This xhr factory is not the best I have see.
        /// You may wish to replace it with another or
        /// use your favorite ajax library to make the
        /// call.
        /// </summary>
        var xhr;

        if (window.XMLHttpRequest) {
            xhr = new XMLHttpRequest();
        }
        else if (window.ActiveXObject) {
            xhr = new ActiveXObject('Microsoft.XMLHTTP');
        }
        else {
            throw new Error("Could not create XMLHttpRequest object.");
        }
        return xhr;
    },


    auditSession: function(key) {
        /// <summary>
        /// Make a request that will be serviced by the audit module to determine the 
        /// state of the current FormsAuthentication ticket or Asp.Net session 
        ///
        /// The return value is a JavaScript date, in numeric form, that represents the
        /// expiration of the item specified by key.
        /// Just cast it to date, i.e. new Date(parseFloat(xhr.resposeText))
        /// </summary>
        /// <param name="key" type="String">
        /// the server key for the item to audit.
        ///
        /// use ".formsauthticket" to get the expiration dateTime for the forms authentication
        /// ticket, if any.
        ///
        /// use ".aspnetsession" to get the expiration of the current ASP.Net session.
        ///
        /// Both have convenience members on this object.
        /// </param>

        var xhr = AsynchronousSessionAuditor.createXHR();

        xhr.open("GET", key, true);

        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                if (xhr.status != 200) {
                    AsynchronousSessionAuditor.errorCallback(key, xhr);
                }
                else {

                    var timeout = parseFloat(xhr.responseText)
                    if (isNaN(timeout) || (new Date(timeout) < new Date())) {
                        AsynchronousSessionAuditor.timeoutCallback(key, xhr);
                    }
                    else {
                        AsynchronousSessionAuditor.statusCallback(xhr.responseText);
                    }
                }

            }
        };
        xhr.send(null);
    },

    init: function(key, statusCallback) {
        // set the statusCallback member for reference.
        AsynchronousSessionAuditor.statusCallback = statusCallback;
        // check right now
        AsynchronousSessionAuditor.auditSession(key);
        // and recurring
        window.setInterval((function() { AsynchronousSessionAuditor.auditSession(key) }), AsynchronousSessionAuditor.pollingInterval);
    }
};



function callScriptMethod(url) {
    /// <summary>
    /// 
    /// Simply makes a bogus ScriptService call to a void PageMethod name DoSomething simulating
    /// an async (Ajax) call.
    /// This resets the session cookie in the same way a postback or refresh would.
    ///
    /// The same would apply to a ScriptService enabled XML Webservice call.
    /// </summary>

    var xhr = AsynchronousSessionAuditor.createXHR();
    xhr.open("POST", url, true);
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
            if (xhr.status != 200) {
                alert("script method call failed:" + xhr.statusText);
            }
        }
    };
    xhr.setRequestHeader("content-type", "application/json");
    var postData = null;
    xhr.send(postData);
}


